class Compiler{
    constructor(vm){
        this.el = vm.$el
        this.vm = vm
        this.compile(this.el)
    }

    compile(el){
        //遍历传入的dom对象的所有结点，并且去判断这些节点  1.如果是文本节点，解析插值表达式 2.如果是元素节点，解析指令
        const nodes = el.childNodes
        // console.dir(el)
        Array.from(nodes).forEach((node)=>{
            
            if( this.isTextNode(node) ){
                // console.log(node);
                this.compileText(node)
            }else if( this.isElementNode(node) ){
                this.compileElement(node)
            }
            // 判断当前node 是否有子节点,如果有,递归调用 compile方法去处理 el中的深层的子节点
            if( node.childNodes && node.childNodes .length>0 ){
                this.compile(node)
            }
        })
    }
    compileElement(node){
        //编译元素节点，解析指令
        let attrs = node.attributes
        // 遍历所有的属性节点
        Array.from(attrs).forEach((attr)=>{
            let attrName = attr.name
            if(this.isDirective(attrName)){
                // debugger
                let name = attrName.split(':')[0].substr(2)
                if(name == 'on'){
                    name = 'on'+attrName.split(':')[1]
                }
                this.update(node , name , attr.value )
            }
        })
    }
    update(node , name , key){
        let updateFn = this[name+'Update']
        updateFn.call(this,node , this.vm[key] , key , name)
    }
    textUpdate(node , value , key){
        node.textContent = value
        new Watcher(this.vm , key , (newValue)=>{
            node.textContent = newValue
        } )
    }
    modelUpdate(node , value , key){
        node.value = value
        new Watcher(this.vm , key , (newValue)=>{
            node.value = newValue
        } )

        node.addEventListener('input' , ()=>{
            this.vm[key] = node.value
        })
    }
    /**
     *  v-html
    */
    htmlUpdate(node , value , key){
        console.dir(node)
        node.innerHTML = value
        new Watcher(this.vm , key , (newValue)=>{
            node.innerHTML = newValue
        } )
    }
    /**
     *  v-on
    */
     onclickUpdate(node , value , key, name){
        console.dir(node)
        node[name] = value
        new Watcher(this.vm , key , (newValue)=>{
            node.name = newValue
        } )
    }

    compileText(node){  //编译文本节点，解析差值表达式
        
        // 创建正则表达式 ; 1:匹配插值表达式,2:将花括号中变量名字提取出来
        const reg = /\{\{(.+?)\}\}/
        const content = node.textContent
        if(reg.test(content)){
            const key = RegExp.$1.trim()
            node.textContent = content.replace(reg , this.vm[key])
            // 创建watcher对象，当数据改变更新视图
            // 而更新视图的本质就是拿到数据操作dom,而dom操作在compiler中进行,在compiler中找到把数据渲染到dom的位置,在这里添加观察者
            // 因为我们的指令和插值表达式都是依赖于数据的,所有视图中依赖数据的位置都需要添加watcher对象,才能在数据发生变化时收到dep的通知拿到新数据在对应的dom中更新视图
            new Watcher(this.vm , key , (newValue)=>{
                node.textContent = newValue
            } )
        }        
    }
    isDirective(attrName){
        // 判断元素属性是否是指令
        return attrName.startsWith('v-')
    }
    isTextNode(node){
        // 判断节点是否是文本节点
        return node.nodeType === 3
    }
    isElementNode(node){
        return node.nodeType === 1
    }
}